package cn.tedu.aiumall.order.webapi.service.impl;

import cn.tedu.aiumall.common.exception.AiuMallServiceException;
import cn.tedu.aiumall.common.pojo.order.dto.OrderAddDTO;
import cn.tedu.aiumall.common.pojo.order.dto.OrderItemAddDTO;
import cn.tedu.aiumall.common.pojo.order.dto.OrderListTimeDTO;
import cn.tedu.aiumall.common.pojo.order.dto.OrderStateUpdateDTO;
import cn.tedu.aiumall.common.pojo.order.model.OmsCart;
import cn.tedu.aiumall.common.pojo.order.model.OmsOrder;
import cn.tedu.aiumall.common.pojo.order.model.OmsOrderItem;
import cn.tedu.aiumall.common.pojo.order.vo.OrderAddVO;
import cn.tedu.aiumall.common.pojo.order.vo.OrderDetailVO;
import cn.tedu.aiumall.common.pojo.order.vo.OrderListVO;
import cn.tedu.aiumall.common.restful.JsonPage;
import cn.tedu.aiumall.common.restful.ResponseCode;
import cn.tedu.aiumall.order.service.IOmsCartService;
import cn.tedu.aiumall.order.service.IOmsOrderService;
import cn.tedu.aiumall.order.webapi.mapper.OmsOrderItemMapper;
import cn.tedu.aiumall.order.webapi.mapper.OmsOrderMapper;
import cn.tedu.aiumall.order.webapi.security.LoginPrincipal;
import cn.tedu.aiumall.order.webapi.utils.IdGeneratorUtils;
import cn.tedu.aiumall.product.order.IForOrderSkuService;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

@DubboService
@Service
@Slf4j
public class OmsOrderServiceImpl implements IOmsOrderService {

    @Autowired
    private OmsOrderMapper omsOrderMapper;

    @Autowired
    private OmsOrderItemMapper omsOrderItemMapper;

    @Autowired
    private IOmsCartService omsCartService;

    @DubboReference
    private IForOrderSkuService dbuuoSkuService;

    @GlobalTransactional
    @Override
    public OrderAddVO addOrder(OrderAddDTO orderAddDTO) {
        OmsOrder order=new OmsOrder();
        BeanUtils.copyProperties(orderAddDTO,order);
        loadOrder(order);

        List<OrderItemAddDTO> itemAddDTOs = orderAddDTO.getOrderItems();
        if (itemAddDTOs==null || itemAddDTOs.isEmpty()){
            throw new AiuMallServiceException(ResponseCode.BAD_REQUEST,"订单中必须至少包含一个商品");
        }
        List<OmsOrderItem> omsOrderItems=new ArrayList<>();
        for (OrderItemAddDTO addDTO:itemAddDTOs){
            OmsOrderItem orderItem=new OmsOrderItem();
            BeanUtils.copyProperties(addDTO,orderItem);
            Long itemId= IdGeneratorUtils.getDistributeId("order_item");
            orderItem.setId(itemId);
            orderItem.setOrderId(order.getId());
            omsOrderItems.add(orderItem);
            Long skuId=orderItem.getSkuId();
            int rows=dbuuoSkuService.reduceStockNum(skuId,orderItem.getQuantity());
            if (rows==0){
                log.warn("商品skuId:{},库存不足!",skuId);
                throw new AiuMallServiceException(ResponseCode.BAD_REQUEST,"库存不足");
            }
            OmsCart omsCart=new OmsCart();
            omsCart.setUserId(order.getUserId());
            omsCart.setSkuId(skuId);
            omsCartService.removeUserCarts(omsCart);
        }
        omsOrderMapper.insertOrder(order);
        omsOrderItemMapper.insertOrderItemList(omsOrderItems);
        OrderAddVO addVO=new OrderAddVO();
        addVO.setId(order.getId());
        addVO.setSn(order.getSn());
        addVO.setCreateTime(order.getGmtOrder());
        addVO.setPayAmount(order.getAmountOfActualPay());

        return addVO;
    }

    private void loadOrder(OmsOrder order) {
        Long id= IdGeneratorUtils.getDistributeId("order");
        order.setId(id);
        if (order.getUserId()==null){
            order.setUserId(getUserId());
        }
        order.setSn(UUID.randomUUID().toString());
        if (order.getState() == null) {
            order.setState(0);
        }
        LocalDateTime now=LocalDateTime.now();
        order.setGmtOrder(now);
        order.setGmtCreate(now);
        order.setGmtModified(now);
        BigDecimal price=order.getAmountOfOriginalPrice();
        BigDecimal freight=order.getAmountOfFreight();
        BigDecimal discount=order.getAmountOfDiscount();
        BigDecimal actualPay=price.add(freight).subtract(discount);
        order.setAmountOfActualPay(actualPay);
    }

    @Override
    public void updateOrderState(OrderStateUpdateDTO orderStateUpdateDTO) {
        OmsOrder order = new OmsOrder();
        BeanUtils.copyProperties(orderStateUpdateDTO,order);
        omsOrderMapper.updateOrderById(order);
    }

    @Override
    public JsonPage<OrderListVO> listOrdersBetweenTimes(OrderListTimeDTO orderListTimeDTO) {
        validateTimeAndLoadTimes(orderListTimeDTO);
        Long userId=getUserId();
        orderListTimeDTO.setUserId(userId);
        PageHelper.startPage(orderListTimeDTO.getPage(),
                            orderListTimeDTO.getPageSize());

        List<OrderListVO> list= omsOrderMapper.selectOrderBetweenTimes(orderListTimeDTO);

        return JsonPage.restPage(new PageInfo<>(list));
    }

    private void validateTimeAndLoadTimes(OrderListTimeDTO orderListTimeDTO) {
        LocalDateTime start=orderListTimeDTO.getStartTime();
        LocalDateTime end=orderListTimeDTO.getEndTime();
        if (start==null || end==null){
            start=LocalDateTime.now().minusMonths(1);
            end=LocalDateTime.now();
            orderListTimeDTO.setStartTime(start);
            orderListTimeDTO.setEndTime(end);
        }else {
            if (end.toInstant(ZoneOffset.of("+8")).toEpochMilli()<
            start.toInstant(ZoneOffset.of("+8")).toEpochMilli()){
                throw new AiuMallServiceException(ResponseCode.BAD_REQUEST,"结束时间应大于起始时间");
            }
        }

    }

    @Override
    public OrderDetailVO getOrderDetail(Long id) {
        return null;
    }

    //业务逻辑层中有后的当前登录用户信息的需求
    //我们的程序在控制器方法运行前执行的过滤器，过滤器中解析了请求头中包含的JWT
    //解析获得JWT的用户信息后保存到了SpringSecurity的上下文中
    //所以我们可以从SpringSecurity的上下文中获取用户信息
    public LoginPrincipal getUserInfo(){
        //编码获得SpringSecurity上下文中保存的权限
        UsernamePasswordAuthenticationToken authenticationToken=
                (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
        if (authenticationToken==null){
            throw new AiuMallServiceException(ResponseCode.UNAUTHORIZED,"请先登录!");
        }
        //上下文信息确定存在后，获取其中的用户信息
        //这个信息就是有JWT解析获得的
        LoginPrincipal loginPrincipal =
                (LoginPrincipal) authenticationToken.getCredentials();
        return loginPrincipal;
    }

    //业务逻辑层大多数方法需要用户的信息实际就是用户的ID，编写一个获得用户ID的方法方便使用
    public Long getUserId(){
        return getUserInfo().getId();
    }
}
